package com.thx.common.util;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * XML和实体之间的转换以及XML转化为map.
 *
 * @author 资丽
 */
public class JaxbUtil {

  // XML编码格式
  private static final String XMLENCODING = "UTF-8";

  /**
   * JavaBean转换成xml 默认编码UTF-8.
   *
   * @param typeMap 为type的map
   */
  public static String convertToXml(Object obj, Map<String, String> typeMap) {
    return convertToXml(obj, XMLENCODING, typeMap, true);
  }

  /**
   * JavaBean转换成xml 默认编码UTF-8.
   */
  public static String convertToXml(Object obj) {
    return convertToXml(obj, XMLENCODING, null, false);
  }

  /**
   * JavaBean转换成xml.
   *
   * @param isAdd 是否添加type
   */
  public static String convertToXml(Object obj, String encoding, Map<String, String> typeMap,
                                    boolean isAdd) {
    String result = null;
    try {
      JAXBContext context = JAXBContext.newInstance(obj.getClass());
      Marshaller marshaller = context.createMarshaller();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化生成的xml串
      marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding); // 编码格式,"UTF-8"
      marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);// 默认false表示xml指令存在
      StringWriter writer = new StringWriter();
      marshaller.marshal(obj, writer);
      if (isAdd) {
        result = addTypeToElement(writer.toString(), typeMap);
      } else {
        result = writer.toString();
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return result;
  }

  /**
   * xml 转换成 JavaBean.
   */
  @SuppressWarnings("unchecked")
  public static <T> T converyToJavaBean(String xml, Class<T> cls) {
    T bean = null;
    try {
      JAXBContext context = JAXBContext.newInstance(cls);
      Unmarshaller unmarshaller = context.createUnmarshaller();
      bean = (T) unmarshaller.unmarshal(new StringReader(xml));
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return bean;
  }

  /**
   * 给节点添加. 例如
   * <pre>
   *   type="string"
   * </pre>
   */
  public static String addTypeToElement(String xml, Map<String, String> typeMap) {
    try {
      Document doc = DocumentHelper.parseText(xml);
      Element root = doc.getRootElement();
      getElementList(root, typeMap);
      StringWriter stringWriterOut = new StringWriter();
      OutputFormat format = OutputFormat.createPrettyPrint();
      XMLWriter writer = new XMLWriter(stringWriterOut, format);
      writer.write(doc);
      writer.close();
      return stringWriterOut.toString();
    } catch (DocumentException ex) {
      // TODO Auto-generated catch block
      ex.printStackTrace();
    } catch (IOException ex) {
      // TODO Auto-generated catch block
      ex.printStackTrace();
    }

    return null;
  }

  /**
   * 获取节点列表.
   */
  public static void getElementList(Element element, Map<String, String> typeMap) {
    @SuppressWarnings("unchecked")
    List<Element> elements = element.elements();
    // 没有子元素
    if (elements.isEmpty()) {
      if (typeMap == null) {
        element.addAttribute("type", "string");
      } else {
        element.addAttribute("type",
            StringUtils.isNotBlank(typeMap.get(element.getName())) ? typeMap.get(
                element.getName()) : "string");
      }
    } else {
      // 有子元素
      for (Element elem : elements) {
        // 递归遍历
        getElementList(elem, typeMap);
      }
    }
  }

  /**
   * xml 转换到 map.
   */
  public static Map<String, String> xml2Map(String xml) {

    Map<String, String> values = new HashMap<String, String>();
    try {
      String tmpXml = StringEscapeUtils.unescapeHtml3(xml);
      int start = tmpXml.indexOf("<?");
      int end = tmpXml.indexOf("?>");
      String title = tmpXml.substring(start, end + 1);
      String res = tmpXml.replace(title, "");
      String finalXml = "<?xml version='1.0' encoding='UTF-8'?>" + res;
      Document doc = DocumentHelper.parseText(finalXml);
      Element root = doc.getRootElement();
      getElementValues(root, values);
    } catch (DocumentException ex) {
      // TODO Auto-generated catch block
      ex.printStackTrace();
    }
    return values;
  }

  /**
   * 获取节点值.
   */
  public static Map<String, String> getElementValues(Element element, Map<String, String> values) {
    @SuppressWarnings("unchecked")
    List<Element> elements = element.elements();
    // 没有子元素
    if (elements.isEmpty()) {
      values.put(element.getName(), element.getStringValue());
    } else {
      // 有子元素
      for (Element elem : elements) {
        // 递归遍历
        getElementValues(elem, values);
      }
    }
    return values;
  }
}
